import wx

from wx.lib.scrolledpanel import ScrolledPanel
from wx.lib.msgpanel import MessagePanel

import extern.customtreectrl as CT
import extern.aui as aui

from widgets import DocstringsSTC, NotebookWidget, StaticTextImage, DiffPage
from widgets import DiagramPanel
from utilities import MakeInheritanceDiagram

from constants import _globalIcons, _panelColumns, _hasDOT


class NotebookPage(aui.AuiNotebook):

    def __init__(self, parent, package_class, other_package_class=None):
        
        aui.AuiNotebook.__init__(self, parent)

        self.MainFrame = wx.GetTopLevelParent(self)
        self.SetProperties()
        self.BuildNBImageList()

        self.package_class = package_class
        self.other_package_class = other_package_class
        self.deleting = False

        self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
        

    def Freeze(self): 

        if not 'wxGTK' in wx.PlatformInfo:
            return super(NotebookPage, self).Freeze() 


    def Thaw(self):

        if not 'wxGTK' in wx.PlatformInfo:
            return super(NotebookPage, self).Thaw()         


    def SetAGWWindowStyleFlag(self, flag):

        flag &= ~aui.AUI_NB_TAB_FLOAT
        aui.AuiNotebook.SetAGWWindowStyleFlag(self, flag)
                

    def BuildNBImageList(self):
        """ Builds a fake image list for aui.AuiNotebook. """

        # One day someone will explain why it doesn't handle wx.ImageList
        # like every other Book.
        self.nbBottomImageList = []
        for png in _globalIcons:
            bmp = self.MainFrame.CreateBitmap(png)
            self.nbBottomImageList.append(bmp)


    def SetProperties(self):

        self.SetUniformBitmapSize((16, 16))     
        self.SetAGWWindowStyleFlag(self.MainFrame.notebook_style)
        notebook_art = self.MainFrame.notebook_art

        if notebook_art == 0:
            self.SetArtProvider(aui.AuiDefaultTabArt())

        elif notebook_art == 1:
            self.SetArtProvider(aui.FF2TabArt())
        
        elif notebook_art == 2:
            self.SetArtProvider(aui.VC71TabArt())

        elif notebook_art == 3:
            self.SetArtProvider(aui.VC8TabArt())

        elif notebook_art == 4:
            self.SetArtProvider(aui.ChromeTabArt())


    def CloseAllTabs(self):

        self.deleting = True

        for indx in xrange(self.GetPageCount()-1, -1, -1):
            self.DeletePage(indx)
            
        self.deleting = False


    def FindPage(self, klass):

        for indx in xrange(self.GetPageCount()):
            page = self.GetPage(indx)
            if page.klass == klass:
                return indx

        return wx.NOT_FOUND
    

    def NewPage(self, treeItem):

        klass1, klass2 = treeItem.GetData(), None
        if isinstance(klass1, list):
            klass1, klass2 = klass1
        
        existing = self.FindPage(klass1)

        if existing >= 0:
            self.SetSelection(existing)
            return

        if klass2 is not None and klass2 is not klass1:
            page = DiffPage(self, klass1, klass2, treeItem)
        else:
            panel = klass1.GetObject().split("/")[0]
            page = eval('%sPanel'%panel)(self, treeItem, panel)

        image = self.nbBottomImageList[klass1.kind]
        self.AddPage(page, klass1.GetShortName(), True, image)


    def OnPageChanged(self, event):

        if self.deleting:
            return
        
        selection = event.GetSelection()

        if selection >= 0:
            page = self.GetPage(selection)
            wx.CallAfter(page.ResizeWidgets)

            treeItem = page.treeItem
            self.MainFrame.dbTree.MakeCurrent(treeItem)
        

class BasePanel(ScrolledPanel):

    def __init__(self, parent, treeItem, name):    

        ScrolledPanel.__init__(self, parent, name=name)

        self.MainFrame = wx.GetTopLevelParent(self)
        self.treeItem = treeItem
        klass = treeItem.GetData()

        if isinstance(klass, list):
            klass = klass[0]

        self.klass = klass            
        
        self.paramList = None

        bigFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        bigFont.SetPointSize(bigFont.GetPointSize()+2)
        bigFont.SetWeight(wx.BOLD)

        self.bigFont = bigFont


    def MakeGeneralDescription(self):    

        descBmp = self.MainFrame.CreateBitmap("description")
        self.descStatic = StaticTextImage(self, "General description", descBmp, style=wx.BORDER_THEME)
        self.descStatic.SetFont(self.bigFont)
        
        klass = self.klass

        values = klass.FormatOutput()
        columns = _panelColumns[self.GetName()]

        self.list = NotebookWidget(self, len(values))

        for columnName, staticType in columns:
            self.list.AddHeader(columnName)

        index = 0

        for columnName, staticType in columns:

            if columnName == "Kind":
                bmpName = _globalIcons[klass.kind]
            elif columnName == "Parent":
                if klass.parent:
                    bmpName = _globalIcons[klass.parent.kind]
                else:
                    bmpName = 'noparent'
            else:
                bmpName = columnName.split()[0].lower()

            bmp = self.MainFrame.CreateBitmap(bmpName)

            value = values[index]
            self.list.Add(value, bmp, staticType)

            index += 1            

        self.list.Finish()


    def MakeDocstrings(self, insert=''):

        docBmp = self.MainFrame.CreateBitmap("docstrings")

        text = 'Docstrings'
        if insert:
            text = 'Signature & docstrings'
            
        self.docsStatic = StaticTextImage(self, text, docBmp, style=wx.BORDER_THEME)
        self.docsStatic.SetFont(self.bigFont)
        
        klass = self.klass        
        self.docs = DocstringsSTC(self)

        comments = ''
        if klass.comments:
            comments = '%s'%klass.comments
            
        self.docs.SetText('%s%s"""\n%s\n"""'%(comments, insert, klass.docs))

        if insert.strip():
            numChars = insert.find("(") + 1
            self.docs.SetWrapStartIndent(numChars)
            
        self.docs.SetReadOnly(True)


    def DoLayout(self):

        mainSizer = wx.BoxSizer(wx.VERTICAL)

        mainSizer.Add(self.descStatic, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10)
        mainSizer.Add(self.list, 0, wx.EXPAND|wx.ALL, 10)
        mainSizer.Add((0, 10))
        mainSizer.Add(self.docsStatic, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10)
        mainSizer.Add(self.docs, 1, wx.EXPAND|wx.ALL, 10)
        self.SetSizer(mainSizer)
        mainSizer.Layout()


    def Finish(self):

        self.SetupScrolling(scroll_x=True, scroll_y=True)


    def ResizeWidgets(self):

        for widget in [self.list, self.paramList]:
            if widget is None:
                continue
            
            size = widget.GetSize()
            widget.SetSize((size.x+1, size.y+1))
            widget.SetSize(size)
            widget.Refresh()
            widget.Update()
        
    
class AttributePanel(BasePanel):
    
    def __init__(self, parent, treeItem, name):

        BasePanel.__init__(self, parent, treeItem, name=name)

        self.MakeGeneralDescription()
        self.MakeDocstrings()
        self.DoLayout()

        self.Finish()        
        

PropertyPanel = AttributePanel


class MethodPanel(BasePanel):
    
    def __init__(self, parent, treeItem, name):

        BasePanel.__init__(self, parent, treeItem, name=name)

        self.MakeGeneralDescription()

        signature = self.klass.signature
        if "@" in signature:
            indx = signature.index(" def ")
            signature = signature[0:indx] + "\n" + signature[indx+1:]
        
        self.MakeDocstrings(insert=signature+"\n")

        if self.klass.arguments:
            self.MakeParameterTable()
        
        self.DoLayout()
        self.Finish()


    def MakeParameterTable(self):

        values = self.klass.arguments
        columns = [u'Name', u'Value (repr)', u'Value (eval)']

        boldFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        boldFont.SetWeight(wx.BOLD)
        
        self.paramList = NotebookWidget(self, 3, len(values)+1)

        for columnName in columns:
            bmpName = "param_%s"%(columnName.split()[-1].replace("(", "").replace(")", "").lower())
            bmp = self.MainFrame.CreateBitmap(bmpName)
            self.paramList.AddHeader(columnName, bmp)

        invalid = wx.NullBitmap
        
        for name, repr_val, eval_val in values:
            static = self.paramList.Add(name, invalid, 0)
            self.paramList.Add(repr_val, invalid, 0)
            self.paramList.Add(eval_val, invalid, 1)

            static.SetFont(boldFont)
            
        self.paramList.Finish()

            
    def DoLayout(self):

        mainSizer = wx.BoxSizer(wx.VERTICAL)

        mainSizer.Add(self.descStatic, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10)
        mainSizer.Add(self.list, 0, wx.EXPAND|wx.ALL, 10)
        mainSizer.Add((0, 10))
        mainSizer.Add(self.docsStatic, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10)

        if self.klass.arguments:
            subSizer = wx.BoxSizer(wx.HORIZONTAL)
            subSizer.Add(self.docs, 3, wx.EXPAND|wx.RIGHT, 10)
            subSizer.Add(self.paramList, 1)
            mainSizer.Add(subSizer, 1, wx.EXPAND|wx.ALL, 10)
        else:        
            mainSizer.Add(self.docs, 1, wx.EXPAND|wx.ALL, 10)
            
        self.SetSizer(mainSizer)
        mainSizer.Layout()


class ClassPanel(BasePanel):
    
    def __init__(self, parent, treeItem, name):

        BasePanel.__init__(self, parent, treeItem, name=name)

        self.MakeGeneralDescription()
        self.MakeClassTree()
        self.MakeDocstrings(insert=self.klass.signature+"\n")

        self.diagramPanel = None
        
        if _hasDOT and self.klass.inheritance_diagram:
            self.MakeInheritanceDiagram()
        
        self.DoLayout()

        self.Finish()        


    def MakeInheritanceDiagram(self):

        diagram = self.klass.inheritance_diagram
        graph = diagram.generate_dot()
        pngFile, errStr = MakeInheritanceDiagram(graph)

        if errStr is None:
            self.diagramPanel = DiagramPanel(self, pngFile)
        else:
            self.MainFrame.SendMessage(errStr, pngFile)

            if "Warning" in errStr:
                flags = wx.ICON_WARNING
            else:
                flags = wx.ICON_ERROR
            
            self.diagramPanel = MessagePanel(self, pngFile, errStr, flags)

            
    def MakeClassTree(self):

        klass = self.klass
        
        treeBmp = self.MainFrame.CreateBitmap("sub_super")
        self.treeStatic = StaticTextImage(self, u'Sub & super classes', treeBmp, style=wx.BORDER_THEME)
        self.treeStatic.SetFont(self.bigFont)

        self.widgets, self.statics = [], []
        style = wx.TE_READONLY|wx.TE_MULTILINE|wx.BORDER_THEME|wx.TE_RICH2

        normalFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        italicFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        italicFont.SetStyle(wx.ITALIC)
        boldFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        boldFont.SetWeight(wx.BOLD)

        self.boldFont = boldFont        
        
        for indx, item in enumerate([klass.subClasses, klass.superClasses]):

            text = (indx == 0 and ["subclasses"] or ["superclasses"])[0]

            if item:
                value = u''
                for v in item:
                    value += u"- %s\n"%v
                font = normalFont
            else:
                value = 'No %s found'%text
                font = italicFont

            textCtrl = wx.TextCtrl(self, -1, value, style=style)
            textCtrl.SetFont(font)
            bmp = self.MainFrame.CreateBitmap(text)
            static = StaticTextImage(self, "Known %s"%text, bmp, style=wx.NO_BORDER)
            static.SetFont(boldFont)
            
            self.statics.append(static)
            self.widgets.append(textCtrl)

        bmp = self.MainFrame.CreateBitmap("tree")
        static = StaticTextImage(self, "Class tree", bmp, style=wx.NO_BORDER)
        static.SetFont(boldFont)
        self.statics.append(static)

        tree = CT.CustomTreeCtrl(self, -1, style=wx.BORDER_THEME,
                                 agwStyle=wx.TR_DEFAULT_STYLE|wx.TR_HIDE_ROOT|wx.TR_HAS_VARIABLE_ROW_HEIGHT|wx.TR_FULL_ROW_HIGHLIGHT)

        imglist = wx.ImageList(16, 16)        
        for png in ['folder', 'klass']:
            imglist.Add(self.MainFrame.CreateBitmap(png))

        tree.AssignImageList(imglist)
        tree.SetBackgroundColour(wx.WHITE)
        tree.EnableSelectionVista(True)
        tree.SetSpacing(10)

        self.root = tree.AddRoot("")        
        self.tree = tree
        self.item = self.root
        self.widgets.append(tree)
        
        self.BuildSubTrees(klass.class_tree)
        self.HighlightCurrent(self.root)
        self.tree.ExpandAll()
        

    def BuildSubTrees(self, class_tree):

        name = self.klass.name            
        for tree in class_tree:
            if isinstance(tree[0], list):
                self.BuildSubTrees(tree)
            else:
                newitem = self.item = self.tree.AppendItem(self.item, tree[0], image=0)
                    
        self.item = self.root
        

    def HighlightCurrent(self, item):

        klass = self.klass
        tree = self.tree
        
        child, cookie = tree.GetFirstChild(item)

        while child:
            if child.GetText() == klass.name and not tree.ItemHasChildren(child):
                self.tree.SetItemFont(child, self.boldFont)
                self.tree.SetItemImage(child, 1)

            self.HighlightCurrent(child)
            child, cookie = tree.GetNextChild(item, cookie)
            

    def DoLayout(self):

        mainSizer = wx.BoxSizer(wx.VERTICAL)

        mainSizer.Add(self.descStatic, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10)
        mainSizer.Add(self.list, 0, wx.EXPAND|wx.ALL, 10)
        mainSizer.Add((0, 10))

        mainSizer.Add(self.treeStatic, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10)
        flexGrid = wx.FlexGridSizer(rows=2, cols=3, hgap=10, vgap=3)

        for static in self.statics:
            flexGrid.Add(static, 0, wx.EXPAND)

        for widget in self.widgets:
            flexGrid.Add(widget, 1, wx.EXPAND)

        for col in xrange(3):
            flexGrid.AddGrowableCol(col)

        flexGrid.AddGrowableRow(1)
        
        mainSizer.Add(flexGrid, 3, wx.EXPAND|wx.ALL, 10)
        mainSizer.Add((0, 10))
        
        mainSizer.Add(self.docsStatic, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10)
        mainSizer.Add(self.docs, 4, wx.EXPAND|wx.ALL, 10)

        if self.diagramPanel is not None:
            diagramBmp = self.MainFrame.CreateBitmap("inheritance")
            self.diagramStatic = StaticTextImage(self, "Inheritance diagram", diagramBmp, style=wx.BORDER_THEME)
            self.diagramStatic.SetFont(self.bigFont)
            mainSizer.Add((0, 10))
            mainSizer.Add(self.diagramStatic, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10)
            mainSizer.Add(self.diagramPanel, 6, wx.EXPAND|wx.ALL, 10)

        self.SetSizer(mainSizer)
        mainSizer.Layout()


class ModulePanel(BasePanel):
    
    def __init__(self, parent, treeItem, name):

        BasePanel.__init__(self, parent, treeItem, name=name)

        self.MakeGeneralDescription()
        self.MakeDocstrings()

        if _hasDOT and "Py" in name and self.klass.inheritance_diagram:
            self.MakeInheritanceDiagram()
            self.DoLayout()
        else:
            BasePanel.DoLayout(self)

        self.Finish()


    def MakeInheritanceDiagram(self):

        diagram = self.klass.inheritance_diagram
        graph = diagram.generate_dot()
        pngFile, errStr = MakeInheritanceDiagram(graph)

        if errStr is None:
            self.diagramPanel = DiagramPanel(self, pngFile)
        else:
            self.MainFrame.SendMessage(errStr, pngFile)
            if "Warning" in errStr:
                flags = wx.ICON_WARNING
            else:
                flags = wx.ICON_ERROR
            
            self.diagramPanel = MessagePanel(self, pngFile, errStr, flags)


    def DoLayout(self):

        diagramBmp = self.MainFrame.CreateBitmap("inheritance")
        self.diagramStatic = StaticTextImage(self, "Inheritance diagram", diagramBmp, style=wx.BORDER_THEME)
        self.diagramStatic.SetFont(self.bigFont)

        mainSizer = wx.BoxSizer(wx.VERTICAL)

        mainSizer.Add(self.descStatic, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10)
        mainSizer.Add(self.list, 0, wx.EXPAND|wx.ALL, 10)
        mainSizer.Add((0, 10))
        mainSizer.Add(self.docsStatic, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10)
        mainSizer.Add(self.docs, 1, wx.EXPAND|wx.ALL, 10)
        mainSizer.Add((0, 10))
        mainSizer.Add(self.diagramStatic, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10)
        mainSizer.Add(self.diagramPanel, 2, wx.EXPAND|wx.ALL, 10)
            
        self.SetSizer(mainSizer)
        mainSizer.Layout()
        

Py_ModulePanel = ModulePanel
Pyc_ModulePanel = ModulePanel
Pyd_ModulePanel = ModulePanel
Pyw_ModulePanel = ModulePanel
PackagePanel = ModulePanel
LibraryPanel = ModulePanel

